//
//  OneICMPPingAction.m
//  iOSLaboratory
//
//  Created by yangshansi on 2017/4/25.
//  Copyright © 2017年 WiLL. All rights reserved.
//

#import "OneIcmpPingAction.h"

#import "SimplePing.h"

@implementation OneIcmpPingAction


/******************************************************************************/
/**** Customized Method                                                    ****/
/******************************************************************************/
#pragma mark - Customized Method

- (BOOL)doOnePing
{
    NSString *host = [self formatHostFromString:self.hostName];
    
    NSLog(@"format host: %@", host);

    self.pinger = [[SimplePing alloc] initWithHostName:host];
    self.pinger.addressStyle = SimplePingAddressStyleAny;
    self.pinger.delegate = self;
    [self.pinger start];
    
    self.timeoutTimer = [NSTimer timerWithTimeInterval:self.timeout
                                                target:self
                                              selector:@selector(onTimeout:)
                                              userInfo:self.timeoutTimer
                                               repeats:NO];
    
    [[NSRunLoop currentRunLoop] addTimer:self.timeoutTimer forMode:NSRunLoopCommonModes];
    
    // 为当前子线程设置并启动RunLoop, 避免子线程在此处执行完毕后退出
    if ([NSThread isMainThread] == NO)
    {
        while (self.timeoutTimer != nil)
        {
            [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
                                     beforeDate:[NSDate dateWithTimeIntervalSinceNow:1]];
        }
    }
    NSLog(@"%@ Pinger start thread finish~", [NSThread currentThread].name);
    
    [self.pinger stop];
    self.pinger.delegate = nil;
    self.pinger = nil;
    
    [self.timeoutTimer invalidate];
    self.timeoutTimer = nil;
    
    return YES;
}

- (void)onTimeout:(NSTimer *)timer
{
    NSLog(@"%@ NSTime time out triggered", [NSThread currentThread].name);
    [self.pinger stop];
    self.pinger.delegate = nil;
    self.pinger = nil;
    
    [self.timeoutTimer invalidate];
    self.timeoutTimer = nil;
}

- (NSString *)formatHostFromString:(NSString *)string
{
    NSString *host = nil;
    
    if ([host hasPrefix:@"http://"] ||
        [host hasPrefix:@"https://"])
    {
        NSURL *url = [NSURL URLWithString:self.hostName];
        if (url)
        {
            host = url.host;
        }
    }
    
    if (host == nil)
    {
        NSRange rangeOfDoubleSlash = [self.hostName rangeOfString:@"://"];
        if (rangeOfDoubleSlash.location != NSNotFound &&
            rangeOfDoubleSlash.length > 0)
        {
            host = [self.hostName substringFromIndex:
                    (rangeOfDoubleSlash.location + rangeOfDoubleSlash.length)];
        }
        
        NSRange rangeOfQuestion = [host rangeOfString:@"?"];
        if (rangeOfQuestion.location != NSNotFound &&
            rangeOfQuestion.length > 0)
        {
            host = [host substringToIndex:rangeOfQuestion.location];
        }
        
        NSRange rangeOfSlash = [host rangeOfString:@"/"];
        if (rangeOfSlash.location != NSNotFound &&
            rangeOfSlash.length > 0)
        {
            host = [host substringToIndex:rangeOfSlash.location];
        }
    }
    
    if (host == nil)
    {
        host = string;
    }
    
    return host;
}



/******************************************************************************/
/**** SimplePing Delegate Method                                           ****/
/******************************************************************************/
#pragma mark - SimplePing Delegate Method

- (void)simplePing:(SimplePing *)pinger didStartWithAddress:(NSData *)address
{
    self.ip = [SimplePing displayAddressForAddress:address];
    // check & set current thread runloop
    
    NSString *output = [NSString stringWithFormat:@"start one ping address: %@",self.ip];
    NSLog(@"%@ %@", [NSThread currentThread].name, output);
    
    if (self.pinger)
    {
        [self.pinger sendPingWithData:nil];
    }
    
}

- (void)simplePing:(SimplePing *)pinger
     didSendPacket:(NSData *)packet
    sequenceNumber:(uint16_t)sequenceNumber
{
    self.sendTime = [[NSDate new] timeIntervalSince1970];
    self.packetSize = packet.length;
    if (self.pinger == pinger)
    {
        NSLog(@"%@ #%ld sent, size=%zu",
              [NSThread currentThread].name,
              self.sequenceNumber,
              self.packetSize);
    }
    
}


- (void)          simplePing:(SimplePing *)pinger
didReceivePingResponsePacket:(NSData *)packet
              sequenceNumber:(uint16_t)sequenceNumber
{
    self.recvTime = [[NSDate new] timeIntervalSince1970];
    self.interval = self.recvTime - self.sendTime;
    
    if (self.pinger == pinger)
    {
        NSLog(@"%@ #%ld received, size=%zu, time=%.3f ms",
              [NSThread currentThread].name,
              self.sequenceNumber,
              self.packetSize,
              self.interval*1000);
    }
    
    [self.timeoutTimer invalidate];
    self.timeoutTimer = nil;
    
}

- (void)simplePing:(SimplePing *)pinger didFailWithError:(NSError *)error
{
    if (self.pinger == pinger )
    {
        NSLog(@"%@ failed: %@", [NSThread currentThread].name,
              [SimplePing shortErrorFromError:error]);
    }
    
    // No need to call -stop.  The pinger will stop itself in this case.
    // We do however want to nil out pinger so that the runloop stops.
    
    self.pinger = nil;
}

- (void)simplePing:(SimplePing *)pinger didReceiveUnexpectedPacket:(NSData *)packet
{
    if (self.pinger == pinger)
    {
//        NSLog(@"%@ unexpected packet, size=%zu",
//              [NSThread currentThread].name, (size_t) packet.length);
        
    }
}

- (void) simplePing:(SimplePing *)pinger
didFailToSendPacket:(NSData *)packet
     sequenceNumber:(uint16_t)sequenceNumber
              error:(NSError *)error
{
    if (self.pinger == pinger)
    {
        NSLog(@"%@ #%u send failed: %@",
              [NSThread currentThread].name,
              (unsigned int) sequenceNumber,
              [SimplePing shortErrorFromError:error]);
        
    }
    
}


/******************************************************************************/
/**** Lifecycle Method                                                     ****/
/******************************************************************************/
#pragma mark - Lifecycle Method

- (instancetype)initWithHost:(NSString *)hostName
              sequenceNumber:(NSInteger)sequenceNumber
                     timeout:(NSInteger)timeout
                        data:(NSData *)data
{
    self = [super initWithHost:hostName sequenceNumber:sequenceNumber
                       timeout:timeout data:data];
    if (self)
    {
        
    }
    return self;
}

@end
